﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Web.Script.Serialization;
using System.Xml.Linq;
//
using PerceptiveMCAPI.Types.Internal;
//
namespace PerceptiveMCAPI.Types
{
	public class campaignsOutput : Api_BaseOutput
	{
		public campaignsResults result { get; set; }
		public campaignsParms inputParms { get; private set; }
		// --------------------------------------------------------
		public campaignsOutput( campaignsInput input )
			: base( input )
		{
			inputParms = input.parms;
			result = new campaignsResults();
		}
		// --------------------------------------------------- tostring
		public override string ToString()
		{
			return string.Format( "Campaign count: {0}", this.result.data.Count );
		}

		#region ================================================================== format setup

		// ---- serial
		internal void Format( string api_Request, string api_Response )
		{
			this.api_Request = api_Request;
			this.api_Response = api_Response;
			// ----------------------------------
			if ( this.api_OutputType == EnumValues.OutputType.JSON )
				outputJSON();
			else if ( this.api_OutputType == EnumValues.OutputType.XML )
				outputXML();
		}

		// ---- xmlrpc
		internal void Format( x_campaigns rpcResult )
		{
			this.api_Request = EnumValues.NotSupplied;
			this.api_Response = EnumValues.NotSupplied;
			// ------------------------
			this.result = FormatResults( rpcResult );
		}

		#endregion

		#region ================================================================= Output

		// ---------------------------------------------------------- outputXML
		private void outputXML()
		{
			XElement xml = XElement.Parse( this.api_Response );
			// error check
			Api_Error error = apiSerial.GetXmlOutputError( xml );
			if ( error != null )
			{
				this.api_ErrorMessages.Add( error );
				return;
			}
			// -------------------------------------------- get values
			int it; double dbl; DateTime dt;
			try
			{
				int.TryParse( xml.Element( "total" ).Value, out it );
				result.total = it;
				//
				if ( xml.Element( "data" ).HasElements )
				{
					IEnumerable<XElement> campaigns = xml.Element( "data" ).Elements( "struct" );
					foreach ( XElement entry in campaigns )
					{
						campaignsResults.DataItem cr = new campaignsResults.DataItem();
						// ----------------------------------
						cr.id = entry.Element( "id" ).Value;
						double.TryParse( entry.Element( "web_id" ).Value, out dbl );
						cr.web_id = dbl;
						cr.list_id = entry.Element( "list_id" ).Value;
						double.TryParse( entry.Element( "folder_id" ).Value, out dbl );
						cr.folder_id = dbl;
						double.TryParse( entry.Element( "template_id" ).Value, out dbl );
						cr.template_id = dbl;
						//
						if ( entry.Element( "content_type" ).IsEmpty )
							cr.content_type = EnumValues.content_type.NotSpecified;
						else
							cr.content_type = apiHelper.GetEnumFromString<EnumValues.content_type>( entry.Element( "content_type" ).Value );
						//
						cr.title = entry.Element( "title" ).Value;
						cr.type = apiHelper.GetEnumFromString<EnumValues.campaign_type>( entry.Element( "type" ).Value );
						DateTime.TryParse( entry.Element( "create_time" ).Value, out dt );
						cr.create_time = dt;
						DateTime.TryParse( entry.Element( "send_time" ).Value, out dt );
						cr.send_time = dt;
						int.TryParse( entry.Element( "emails_sent" ).Value, out it );
						cr.emails_sent = it;
						cr.status = apiHelper.GetEnumFromString<EnumValues.campaign_status>( entry.Element( "status" ).Value );
						cr.from_name = entry.Element( "from_name" ).Value;
						cr.from_email = entry.Element( "from_email" ).Value;
						cr.subject = entry.Element( "subject" ).Value;
						cr.to_name = entry.Element( "to_name" ).Value;
						cr.archive_url = entry.Element( "archive_url" ).Value;
						cr.inline_css = ( entry.Element( "inline_css" ).Value.Trim() == "1" ) ? true : false;
						// --------------------------- 
						cr.analytics = entry.Element( "analytics" ).Value;
						cr.analytics_tag = entry.Element( "analytics_tag" ).Value;
						// --------------------------- 
						cr.authenticate = entry.Element( "authenticate" ).Value.Trim() == "1" ? true : false;
						cr.ecomm360 = entry.Element( "ecomm360" ).Value.Trim() == "1" ? true : false;
						cr.auto_tweet = entry.Element( "auto_tweet" ).Value.Trim() == "1" ? true : false;
						if ( !entry.Element( "auto_fb_post" ).IsEmpty )
							cr.auto_fb_post = apiHelper.MakeListFromString( entry.Element( "auto_fb_post" ).Value );
						//
						cr.timewarp = entry.Element( "timewarp" ).Value.Trim() == "1" ? true : false;
						cr.timewarp_schedule = entry.Element( "timewarp_schedule" ).Value ?? "";
						//
						if ( entry.Element( "tracking" ).HasElements )
						{
							XElement tracking = entry.Element( "tracking" );
							cr.tracking.opens = tracking.Element( "opens" ).Value.Trim() == "1" ? true : false;
							cr.tracking.html_clicks = tracking.Element( "html_clicks" ).Value.Trim() == "1" ? true : false;
							cr.tracking.text_clicks = tracking.Element( "text_clicks" ).Value.Trim() == "1" ? true : false;
						}
						cr.segment_text = entry.Element( "segment_text" ).Value;
						// -------------------------------------------------------------------- segments
						XElement so = entry.Element( "segment_opts" );
						if ( so.HasElements )
						{
							cr.segment_opts.match = so.Element( "match" ).Value;
							IEnumerable<XElement> cond = so.Elements( "conditions" ).Descendants( "struct" );
							foreach ( XElement item in cond )
							{
								campaignSegmentCondition cso = new campaignSegmentCondition();
								cso.field = item.Element( "field" ).Value;
								cso.op = item.Element( "op" ).Value;
								cso.value = item.Element( "value" ).Value;
								cr.segment_opts.conditions.Add( cso );
							}
						}
						// ----------------------------------------------------------------- type opts
						XElement type_opts = entry.Element( "type_opts" );
						if ( type_opts.HasElements )
						{
							Dictionary<string, string> opt_entries = new Dictionary<string, string>();
							IEnumerable<XElement> opts = type_opts.Descendants();
							foreach ( XElement item in opts )
							{
								opt_entries.Add( item.Name.LocalName, item.Value );
							}
							cr.type_opts = opt_entries;
						}
						// ---------------------------
						this.result.data.Add( cr );
					}
				}
			}
			catch ( Exception ex )
			{
				this.api_ErrorMessages.Add( apiException.FormatError( ex ) );
			}
		}

		// ---------------------------------------------------------- outputJSON
		private void outputJSON()
		{
			JavaScriptSerializer jss = new JavaScriptSerializer();

			try
			{
				if ( this.api_Response.Contains( EnumValues.JSONErrorString ) )
				{
					Api_Error err = jss.Deserialize<Api_Error>( this.api_Response );
					this.api_ErrorMessages.Add( err );
				}
				else
				{
					x_campaigns jsonResult = jss.Deserialize<x_campaigns>( this.api_Response );
					this.result = FormatResults( jsonResult );
				}
			}
			catch ( Exception ex )
			{
				this.api_ErrorMessages.Add( apiException.FormatError( ex ) );
			}
		}

		// ----------------------------------------------------------------------------- FormatResults
		private campaignsResults FormatResults( x_campaigns x_results )
		{
			campaignsResults campaigns = new campaignsResults();
			campaigns.total = x_results.total;
			//
			// array to generic list
			foreach ( x_campaigns.data_item tc in x_results.data )
			{
				DateTime dt;
				campaignsResults.DataItem campaign = new campaignsResults.DataItem();
				//
				campaign.id = tc.id;
				campaign.web_id = tc.web_id;
				campaign.list_id = tc.list_id;
				campaign.folder_id = tc.folder_id;
				campaign.template_id = tc.template_id;
				if ( !string.IsNullOrEmpty( tc.content_type ) )
					campaign.content_type = apiHelper.GetEnumFromString<EnumValues.content_type>( tc.content_type );
				campaign.title = tc.title;
				campaign.type = apiHelper.GetEnumFromString<EnumValues.campaign_type>( tc.type );
				DateTime.TryParse( tc.create_time, out dt ); campaign.create_time = dt;
				DateTime.TryParse( tc.send_time, out dt ); campaign.send_time = dt;
				campaign.emails_sent = tc.emails_sent;
				campaign.status = apiHelper.GetEnumFromString<EnumValues.campaign_status>( tc.status );
				campaign.from_name = tc.from_name;
				campaign.from_email = tc.from_email;
				campaign.subject = tc.subject;
				campaign.to_name = tc.to_name;
				campaign.archive_url = tc.archive_url;
				campaign.inline_css = tc.inline_css;
				// --------------------------- 
				campaign.analytics = tc.analytics;
				campaign.analytics_tag = tc.analytics_tag;
				//
				campaign.authenticate = tc.authenticate;
				campaign.ecomm360 = tc.ecomm360;
				campaign.auto_tweet = tc.auto_tweet;
				if ( !string.IsNullOrEmpty( tc.auto_fb_post ) )
					campaign.auto_fb_post = apiHelper.MakeListFromString( tc.auto_fb_post );
				campaign.timewarp = tc.timewarp;
				campaign.timewarp_schedule = tc.timewarp_schedule;
				//
				if ( tc.tracking.Count > 0 )
				{
					campaign.tracking.opens = (bool)tc.tracking["opens"];
					campaign.tracking.html_clicks = (bool)tc.tracking["html_clicks"];
					campaign.tracking.text_clicks = (bool)tc.tracking["text_clicks"];
				}
				//
				campaign.segment_text = tc.segment_text;
				// yes, there is text returned by MC, but sometimed I want it RAW!
				campaign.segment_opts = FormatSegmentOptions( tc.segment_opts );
				// -----------------------------------
				campaign.type_opts = FormatTypeOptions( tc.type_opts );
				//
				campaigns.data.Add( campaign );
			}
			return campaigns;
		}

		// -----------------------------------------------------------------------------
		private campaignSegmentOptions FormatSegmentOptions( object segment_opts )
		{
			campaignSegmentOptions SegmentOptions = new campaignSegmentOptions();
			if ( segment_opts == null || segment_opts.GetType().IsArray ) return SegmentOptions;          // empty array for not segmented

			IDictionary seg_opts = segment_opts as IDictionary;
			SegmentOptions.match = seg_opts["match"].ToString();
			object[] opts_obj = seg_opts["conditions"] as object[];
			foreach ( object opt_obj in opts_obj )
			{
				IDictionary opts = opt_obj as IDictionary;
				campaignSegmentCondition cond = new campaignSegmentCondition();
				cond.field = opts["field"].ToString();
				cond.op = opts["op"].ToString();
				cond.value = opts["value"].ToString();
				if ( opts["extra"] != null )
					cond.extra = opts["extra"].ToString();
				SegmentOptions.conditions.Add( cond );
			}
			return SegmentOptions;
		}
		// -----------------------------------------------------------------------------
		private Dictionary<string, string> FormatTypeOptions( object type_opts )
		{
			Dictionary<string, string> opts = new Dictionary<string, string>();
			if ( type_opts == null || type_opts.GetType().IsArray ) return opts;          // empty array for no opts

			IDictionary to = type_opts as IDictionary;
			IDictionaryEnumerator de = to.GetEnumerator();
			string val = "";
			while ( de.MoveNext() )
			{
				if ( de.Value != null )
					val = de.Value.ToString();
				else
					val = "";
				//
				opts.Add( de.Key.ToString(), val );
			}
			return opts;
		}

		#endregion
	}
}
